{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}


(*******************************************************************************

Fonctionnement:
- Chaque planète possède une liste d'action, celle ci est sauvegardée au sein
  même du fichier d'informations des planètes

- Cependant on doit pouvoir exploiter une même liste d'action, par exemple,
  une liste d'action de colonisation de production de Cristal, dans ce cas
  la liste est sauvegardée dans un fichier spécial. Et peut être importé
  facilement pour une planète

- La liste d'action englobe les actions constructible par le chantier
  spatial (défense, et vaisseaux), le laboratoire et les batiments
  Pour le chantier spatial, c'est assez spécial car une liste d'action
  est géré sur le site.
  Pour les deux autres type, on peut construire en paralléle un batiment
  ainsi qu'une recherche. Si par exemple il y a deux batiments puis
  une recherche à faire. Deux cas possible:
  -> Soit il y a assez de ressources pour construire les 3 éléments. En théorie
     on va construire le premier batiment, on va essayer d'éxécuter l'action
     suivante, et on va donc attendre que le premier bat. soit construit.
     puis on contruit le second, et on essai d'exécuter l'action suivante, qui
     est réalisable, donc en paralléle la recherche va s'effectuer.

     Ce qu'il aurait fallu, est que la recherche se fasse en même temps que le
     premier batiment.

  -> Soit il n'y a pas assez de ressources pour construire les 3 éléments. Dans
     ce cas là aucun probléme se pose. Mis à part le fait que si la construction
     est long, et que l'on accumule ainsi assez de ressources pour effectuer
     les deux actions suivantes, la recherche peut s'exécuter sans pour autant
     attendre la fin de la premiere action.

  Ceci dit, tout cela doit être gérer indépendament de cette unité. Car ici
  on ne gère que la liste d'action.
  

*******************************************************************************)
unit modActionManager;

interface

uses Classes, SysUtils, Windows, sFonctionsChaines, modBaseType;

const
    ACTION_BUILD = 0;
    ACTION_ADJUST_RESSOURCE_AUTO = 1;
    ACTION_ADJUST_MANUAL         = 2;

    ACTION_GIDMISC_BEST_RESSOURCE_ACTIVITY_NEXTELEMENT = 8700;
    ACTION_GIDMISC_BEST_RESSOURCE_ACTIVITY_METAL       = 8701;
    ACTION_GIDMISC_BEST_RESSOURCE_ACTIVITY_CRISTAL     = 8702;
    ACTION_GIDMISC_BEST_RESSOURCE_ACTIVITY_DEUTERIUM   = 8703;
    ACTION_GIDMISC_BEST_RESSOURCE_DONTCHANGE_ANYTHING  = 8704;

    ACTION_GIDMISC_START = ACTION_GIDMISC_BEST_RESSOURCE_ACTIVITY_NEXTELEMENT;

    ACTION_STATUS_INVALID   = 0;
    ACTION_STATUS_ENATTENTE = 1;
    ACTION_STATUS_EFFECTUE  = 2;


    // GID disponible plus tard certainement, dans ce cas, le programme vérifie
    // si le GID est disponible, si il ne l'est pas, il passe à l'élément suivant
    // et revérifie si il peut le 'construire'
    ACTION_STATUS_GIDNONDISPONIBLE = 3;

    // GID Non constructible avec la production actuelle
    // (par exemple, 0 prod en deut par heure)
    // mais généralement il y a auto ajustement pour produire le plus vite possible
    // mais il se peut que l'on programme l'usine de robot alors que la mine
    // de deut ne soit pas encore disponible
    ACTION_STATUS_GID_CANTBEBUILDWITHTHISPRODUCTION = 4;



    // Lors de l'utilisation de modification de ressource, celui-ci indique
    // lequel est choisit, les autres sont soit en attente, soit effectué
    ACTION_STATUS_ACTIVE = 5;

    // Lorsque le niveau requis a été dépassé
    ACTION_STATUS_NIVEAUREQ_DEPASSE = 6;

    // Lorsque le niveau requis n'est pas encore atteint
    ACTION_STATUS_NIVEAUREQ_PAS_ATTEINT = 7;


    FNCT_RES_RESSOURCE_INSUFFISANTE      = -255;
    FNCT_RES_AUTRECONSTRUCTION_EN_COURS  = -254;
    FNCT_RES_DO_NEXT_ACTION              =  256;
    FNCT_RES_GID_NON_DISPONIBLE          = -257;


type
    TElementActionItem = record
       // Id inutile en fait
       //Id: integer;

       // GID de l'élément à construire
       GID: integer;

       // Quantité si il s'agit de vaisseau ou de def, 0 ou 1 sinon
       Quantite: integer;

       // Indique si l'action a déjà été effectué, ou pas
       Status: integer;

       // Niveau du batiment/recherche requis pour faire la construction
       // -1 si aucun niveau requis
       NiveauRequis: integer;

       // Date où l'élément a commencé à être construit, ou de la dernière
       // vérification d'existance de GID
       DateDone: int64;

       // Nombre de GID construit au total
       // Ne sert uniquement pour que l'utilisateur se fasse une idée du niveau
       // atteint, la valeur n'est pas sauvegardé
       NiveauAtteint: integer;
    end;





type
    TNiveauArray = array[MIN_GID_ARRAY..MAX_GID_ARRAY] of integer;

    PElementActionItem = ^TElementActionItem;
    TCollectionElementActionItem = class(TList)
    private
       {--------------------------------------------------}
       {Elements spécialisés de la classes}
       FFichier: string;

       // Lorsque la liste est sauvegardée dans un fichier spécial (un
       // fichier base de donnée), ce nom permet de l'identifier
       FNomListe: string;

       FBaseNiveau : TNiveauArray;
       FDebugProc: TsfcProcStatus;

       {--------------------------------------------------}
       {Gestion des pointeurs}
       // Utilisé pour la propriété Itemx
       function GetItemx(Index: integer): TElementActionItem;

       function AddFromLigneLoaded(Ligne: string): boolean;

       procedure DoDebug(const Msg: string);
    public
       property DebugProc : TsfcProcStatus read FDebugProc write FDebugProc;

       
       {--------------------------------------------------}
       {Gestion des pointeurs}
       // *** Ajout de pointeurs
       // Renvoi le pointeur de l'élément ajouté
       function Add(Element: TElementActionItem): PElementActionItem;
      
       // Simple ajout de pointeur
       procedure SimpleAdd(Pointeur: PElementActionItem);


       // *** Suppression de pointeur
       // Libère et supprime le pointeur Index
       // Renvoi True si réussit, False si hors limite ou erreur
       function Delete(Index: integer): boolean;
       function DeleteSimple(Index: integer): boolean;
       
      
       // *** Effacement de la liste de pointeur
       procedure Clear; override;
      
      
       // *** Requete sur la liste de pointeur
       function Get_Item(Index: integer): TElementActionItem;
       property Itemx[Index: integer]: TElementActionItem read GetItemx;
      

      
       {--------------------------------------------------}
       {Procédures et fonctions spécialisées de la classes}
       // Destructeur
       destructor Destroy; override;
       constructor Create;

       procedure CalculNiveauAtteint;

       // Par défaut, tout les niveaux sont à 0
       procedure SetBaseNiveau(Gid, Niveau: integer);

       // Renvoi le "style" de ressource à adapter
       function GetGIDSetRessourceForThisItem(Index: integer; UpdateOtherFlag: boolean): integer;

       // Compte le nombre d'élément pour connaitre le nombre de niveau d'évolution total
       function GetNbItemOfThisType(Gid: integer): integer;

       function GetActionsRestanteAExecuter: integer;

       function SaveToFile(var F: TextFile): integer;
       function LoadFromFile(var F: TextFile): integer;

       function LoadFromDB(Fichier: string; Script: string): integer;
       function SaveToDB(Fichier: string; Script: string): integer;
       function DBEffaceScript(Fichier: string; Script: string): integer;

       procedure SendToDebugAllInfo;

       function GetIndexNextActionToDo(NumeroAfter: integer = 1): integer;
       function GetNextActionToDo: PElementActionItem;

       procedure ResetFlag(FlagGIDIndisponible, FlagProductionFaible: boolean);

       procedure ActionEffectuee(Pointeur: PElementActionItem);

    end;

    
    function mamGetStatusToStrShort(Status: integer): string;

implementation


function mamGetStatusToStrShort(Status: integer): string;
begin

    case Status of
        ACTION_STATUS_INVALID: Result := 'Invalide';
        ACTION_STATUS_ENATTENTE: Result := 'En attente';
        ACTION_STATUS_EFFECTUE : Result := 'Effectué';
        ACTION_STATUS_GIDNONDISPONIBLE : Result := 'Pas disponible';
        ACTION_STATUS_GID_CANTBEBUILDWITHTHISPRODUCTION: Result := 'Impossible';
        else Result := 'Inconnu';
    end;

end;


function mamGetStatusToStr(Status: integer): string;
begin

    case Status of
        ACTION_STATUS_INVALID: Result := 'Invalide';
        ACTION_STATUS_ENATTENTE: Result := 'En attente';
        ACTION_STATUS_EFFECTUE : Result := 'Effectué';
        ACTION_STATUS_GIDNONDISPONIBLE : Result := 'Pas disponible';
        ACTION_STATUS_GID_CANTBEBUILDWITHTHISPRODUCTION: Result := 'Production empeche construction';
        else Result := 'Inconnu';
    end;

end;



{*******************************************************************************
 ******************************************************************************* 
 **               TCollectionElementActionItem                                     **
 *******************************************************************************
 *******************************************************************************}

procedure TCollectionElementActionItem.ActionEffectuee(Pointeur: PElementActionItem);
var i: integer;
begin

    if Pointeur.GID >= ACTION_GIDMISC_START then exit;

    // ON NE DOIT PAS MODIFIER CE FLAG, IL EST MODIFIE
    // AVANT L'APPEL DE LA PROCEDURE, car le flag peut
    // être aussi ACTION_STATUS_GIDNONDISPONIBLE ou
    // ACTION_STATUS_GID_CANTBEBUILDWITHTHISPRODUCTION  ou encore ACTION_STATUS_NIVEAUREQ_PAS_ATTEINT
    // ou tout autre status possible
    //Pointeur.Status := ACTION_STATUS_EFFECTUE;


    if Pointeur.Status = ACTION_STATUS_ENATTENTE then begin
       // cela risque de provoquer une boucle car le prochaine élément
       // disponible sera le même...
       // Dans ce cas là il vaut mieux ne pas appellé cette procédure
       DoDebug('ActionScript - ActionEffectuee - Risque de boucle infinie');
       exit;
    end;

    i := IndexOf(Pointeur);

    if i < 0 then begin
       DoDebug('Erreur critique');
       exit;
    end;

    if i = Count - 1 then begin
       // On peut tout mettre en "Effectué"

    end else begin
       // Recalcul le bon élément pour la Production
       // Pour cela, on obtient le prochain élément
       i := GetIndexNextActionToDo;

       // Et on met à jour les status
       GetGIDSetRessourceForThisItem(i, true);

    end;


end;


procedure TCollectionElementActionItem.ResetFlag(FlagGIDIndisponible, FlagProductionFaible: boolean);
var i: integer;
    cE: PElementActionItem;
begin

    if Count = 0 then exit;

    for i := 0 to Count - 1 do begin
       cE := Items[i];

       if FlagGIDIndisponible then begin
          if cE.Status = ACTION_STATUS_GIDNONDISPONIBLE then
             cE.Status := ACTION_STATUS_ENATTENTE;

       end;

       if FlagProductionFaible then begin
          if cE.Status = ACTION_STATUS_GIDNONDISPONIBLE then
             cE.Status := ACTION_STATUS_ENATTENTE;

       end;

    end;

end;



function TCollectionElementActionItem.GetIndexNextActionToDo(NumeroAfter: integer = 1): integer;
var i, j: integer;
    cE: PElementActionItem;
begin
    Result := -1;

    if Count = 0 then exit;
    if NumeroAfter < 1 then exit;


    j := 0;

    for i := 0 to Count - 1 do begin
       cE := Items[i];

       if cE.Status = ACTION_STATUS_EFFECTUE then Continue;
       if cE.Status = ACTION_STATUS_INVALID then Continue;
       if cE.Status = ACTION_STATUS_GIDNONDISPONIBLE then Continue;
       if cE.Status = ACTION_STATUS_GID_CANTBEBUILDWITHTHISPRODUCTION then Continue;
       if cE.Status = ACTION_STATUS_ACTIVE then Continue;

       if cE.Status =  ACTION_STATUS_ENATTENTE then begin

          // Vérifie le Gid
          if cE.GID >= ACTION_GIDMISC_START then Continue;

          Inc(j);
          if j < NumeroAfter then Continue;

          // Sinon, on doit effectuer celui-ci maintenant
          Result := i;
          exit;
       end;

       
    end;


end;

function TCollectionElementActionItem.GetNextActionToDo: PElementActionItem;
var i: integer;
begin

    i := GetIndexNextActionToDo;

    if NoT(i < 0) then begin
       Result := Items[i];
    end else
       Result := nil;

end;

function TCollectionElementActionItem.GetActionsRestanteAExecuter: integer;
begin
    Result := 0;

    if Count = 0 then exit;

    
end;

procedure TCollectionElementActionItem.DoDebug(const Msg: string);
begin
     if Assigned(FDebugProc) then
        FDebugProc(Msg);
        
end;

procedure TCollectionElementActionItem.SendToDebugAllInfo;
var i : integer;
    cElement: PElementActionItem;
    s: string;
begin

    if Count = 0 then begin
       DoDebug('Aucune action à exécuter');

    end else begin

       for i := 0 to Count - 1 do begin
           cElement := Items[i];


           s := format('%d Qt:%d Status: %s  NivRequis:%d - Date:%d', [cElement.GID, cElement.Quantite, mamGetStatusToStr(cElement.Status), cElement.NiveauRequis, cElement.DateDone]);
           DoDebug(s);
       end;
    end;

    DoDebug('');

end;

function TCollectionElementActionItem.GetNbItemOfThisType(Gid: integer): integer;
var i: integer;
    p: PElementActionItem;
begin

    Result := 0;

    if Count = 0 then exit;

    for i := Count - 1 downto 0 do begin
       p := Items[i];

       if p.GID = Gid then begin
          if p.Quantite > 1 then begin
             Result := Result + p.Quantite;
          end else
             Inc(Result);
       end;

    end;
end;

function TCollectionElementActionItem.GetGIDSetRessourceForThisItem(Index: integer; UpdateOtherFlag: boolean): integer;
var i: integer;
    p: PElementActionItem;
begin

    Result := -1;

    if (Count = 0) or (Index < 0) or (Index >= Count) then begin
       exit;
    end;

    for i := Index downto 0 do begin
       p := Items[i];

       if p.GID >= ACTION_GIDMISC_BEST_RESSOURCE_ACTIVITY_NEXTELEMENT then begin
          Result := p.GID;

          if UpdateOtherFlag = false then begin
             exit;
          end else begin
             p.Status := ACTION_STATUS_ACTIVE;
             break;

          end;

       end;

    end;

    if i > 0 then begin

       Index := i - 1;

       for i := Index downto 0 do begin
          p := Items[i];

          if p.GID >= ACTION_GIDMISC_BEST_RESSOURCE_ACTIVITY_NEXTELEMENT then begin
             p.Status := ACTION_STATUS_EFFECTUE;
          end;

       end;


    end;

end;

procedure TCollectionElementActionItem.CalculNiveauAtteint;
var DaCurrentNiv: TNiveauArray;
    i: integer;
    p: PElementActionItem;
begin

     if Count = 0 then exit;

     // Copie le tableau de base
     for i := MIN_GID_ARRAY to MAX_GID_ARRAY do begin
         DaCurrentNiv[i] := FBaseNiveau[i];
     end;


     for i := 0 to Count - 1 do begin
         p := Items[i];

         if p.GID < MIN_GID_ARRAY then Continue;
         if p.GID > MAX_GID_ARRAY then Continue;



         if p.Quantite > 1 then begin
            DaCurrentNiv[p.GID] := DaCurrentNiv[p.GID] + p.Quantite;
         end else
            Inc(DaCurrentNiv[p.GID]);

         p.NiveauAtteint := DaCurrentNiv[p.GID];
     end;

     
end;

procedure TCollectionElementActionItem.SetBaseNiveau(Gid, Niveau: integer);
begin
    if Gid < MIN_GID_ARRAY then exit;
    if Gid > MAX_GID_ARRAY then exit;

   FBaseNiveau[Gid] := Niveau;
end;


function TCollectionElementActionItem.LoadFromDB(Fichier: string; Script: string): integer;
var FIn: TextFile;
    Ligne: string;
begin

   Result := -2;

   if FileExists(Fichier) = false then exit;

   AssignFile(FIn, Fichier);

   {$I-}
   ReSet(FIn);
   {$I+}

   // IOResult renvoie 0 => cela signifie que la dernière opération d'E/S a réussi
   if NoT(IOResult = 0) then begin
       Result := -1;
       exit;
   end;

   Script := '[' + trim(Script) + ']';

    While NoT(EoF(FIn)) do begin
         // Lit une ligne
         ReadLn(FIn, Ligne);

         Ligne := trim(Ligne);
         if SameText(Script, Ligne) then begin
            // Script trouvé
            Result := LoadFromFile(FIn);
            break;
         end;

    end;

    CloseFile(FIn);

end;


function TCollectionElementActionItem.DBEffaceScript(Fichier: string; Script: string): integer;
var FIn, FOut: TextFile;
    FichierTemp, Ligne: string;
    bDontCopy, bHaveBeenFound : boolean;
begin

    Result := -2;
    if FileExists(Fichier) = false then exit;

    FichierTemp := Fichier + '.x';

    AssignFile(FIn, Fichier);
    AssignFile(FOut, FichierTemp);

    {$I-}
    ReSet(FIn);
    ReWrite(FOut);
    {$I+}

    // IOResult renvoie 0 => cela signifie que la dernière opération d'E/S a réussi
    if NoT(IOResult = 0) then begin
       Result := -1;
       CloseFile(FIn);
       CloseFile(FOut);
       exit;
    end;



    Script := '[' + trim(Script) + ']';

    bDontCopy := false;
    bHaveBeenFound := false;

    While NoT(EoF(FIn)) do begin
         // Lit une ligne
         ReadLn(FIn, Ligne);

         Ligne := trim(Ligne);
         if SameText(Script, Ligne) then begin
            bDontCopy := true;
            bHaveBeenFound := true;
            Continue;
         end;

         if bDontCopy = false then begin
            WriteLn(FOut, Ligne);

         end else begin

            if Ligne = '' then Continue;
            if Ligne[1] = '[' then begin
               bDontCopy := false;
               WriteLn(FOut, Ligne);
            end;

         end;

    end;


    CloseFile(FIn);
    CloseFile(FOut);

    if bHaveBeenFound then begin
       DeleteFile(Pchar(Fichier));
       MoveFile(PChar(FichierTemp), PChar(Fichier));
       Result := 2;
    end;

    Result := 1;


end;


function TCollectionElementActionItem.SaveToDB(Fichier: string; Script: string): integer;
var i: integer;
    F: TextFile;
    FIn: TextFile;
    pElement: PElementActionItem;
    Ligne, FichierTemp: string;
begin

    Result := -2;

    if Fichier = '' then Fichier := FFichier;

    DBEffaceScript(Fichier, Script);


    FichierTemp := Fichier + '.t';

    AssignFile(F, FichierTemp);

    {$I-}
    ReWrite(F);
    {$I+}

    // IOResult renvoie 0 => cela signifie que la dernière opération d'E/S a réussi
    if NoT(IOResult = 0) then begin
       Result := -1;
       exit;
    end;

    WriteLn(F, '[' + Script + ']');

    // Ecrit les données ici
    SaveToFile(F);


    // Ecrit la suite du fichier
    if FileExists(Fichier) then begin
          AssignFile(FIn, Fichier);

          {$I-}
          ReSet(FIn);
          {$I+}

          // IOResult renvoie 0 => cela signifie que la dernière opération d'E/S a réussi
          if NoT(IOResult = 0) then begin
             Result := -1;
             CloseFile(F);
             exit;
          end;


          While NoT(EoF(FIn)) do begin
               // Lit une ligne
               ReadLn(FIn, Ligne);
               WriteLn(F, Ligne);
          end;

          CloseFile(FIn);
          DeleteFile(Pchar(Fichier));
    end;

    // Ferme le fichier
    CloseFile(F);

    // Renome le fichier temporaire
    MoveFile(PChar(FichierTemp), PChar(Fichier));

    // Résultat
    Result := Count;

end;


function TCollectionElementActionItem.AddFromLigneLoaded(Ligne: string): boolean;
var Element: TElementActionItem;
    xPos, i: integer;
    s: string;
begin
    Result := false;

    // 8703=1,1,-1,0

    xPos := pos('=', Ligne);
    if xPos = 0 then exit;

    s := copy(Ligne, 1, xPos - 1);
    if s = '' then exit;
    if NoT(s[1] in sfc_ChiffresSet) then exit;



    try
       Element.GID := StrToInt(s);
    except
       xPos := -1;
    end;

    if xPos = -1 then exit;

    System.Delete(Ligne, 1, xPos);

    i := sfcTokenCount(Ligne, ',');
    if i < 4 then exit;

    Element.Quantite     := sfcTokenGetInt(Ligne, 1, ',', -2);
    Element.Status       := sfcTokenGetInt(Ligne, 2, ',', ACTION_STATUS_INVALID);
    Element.NiveauRequis := sfcTokenGetInt(Ligne, 3, ',', -5);
    Element.DateDone     := sfcTokenGetInt(Ligne, 4, ',', -50);

    if Element.Status       = ACTION_STATUS_INVALID then exit;
    if Element.Quantite     < -1  then exit;
    if Element.NiveauRequis < -1  then exit;
    if Element.DateDone     < -1  then exit;

    Element.NiveauAtteint := 0;

    Add(Element);

    Result := true;

end;


function TCollectionElementActionItem.LoadFromFile(var F: TextFile): integer;
var Ligne: string;
    i: integer;
begin

    Result := 0;

    While NoT(EoF(F)) do begin
         // Lit une ligne
         ReadLn(F, Ligne);

         Ligne := trim(Ligne);
         if Ligne = '' then break;

         if AddFromLigneLoaded(Ligne) then
            Inc(Result);

    end;



end;


function TCollectionElementActionItem.SaveToFile(var F: TextFile): integer;
var i: integer;
    pElement: PElementActionItem;
begin

    Result := -2;

    WriteLn(F, format('s=%d', [Count]));

    for i := 0 to Count - 1 do begin
        pElement := Items[i];

        //
        // Ecriture ici
        //

        WriteLn(F, format('%d=%d,%d,%d,%d', [pElement.GID, pElement.Quantite, pElement.Status, pElement.NiveauRequis, pElement.DateDone]));
    end;

    WriteLn(F, '');

    // Résultat
    Result := Count;

    
end;

constructor TCollectionElementActionItem.Create;
var i: integer;
begin

    // Héritage
    InHerited Create;

    // Code pour l'initialisation ici


    for i := MIN_GID_ARRAY to MAX_GID_ARRAY do
       FBaseNiveau[i] := 0;


    
end;

destructor TCollectionElementActionItem.Destroy;
begin
    // Implémenter le code avant l'héritage de la méthode
    // C'est à dire ici
    
   
    // On appelle NOTRE clear qui lui-même appelle NOTRE Delete qui libère l'espace mémoire
    // avant d'enlever le pointeur de la TList
    // L'héritage de Destroy appelle Clear, mais es-ce le notre ou celui de la classe de base ?
    Clear;
    
    
    // Héritage
    InHerited Destroy;
end;


procedure TCollectionElementActionItem.Clear;
var i: integer;
begin

    if Count > 0 then begin
        For i := Count -1 downto 0 do
            Delete(i);
    end;
    
    inherited Clear;
end;





function TCollectionElementActionItem.Get_Item(Index: integer): TElementActionItem;
var pElement: PElementActionItem;
begin

     if Index < 0 then exit;
     if Index >= Count then exit;

     pElement := Items[Index];     // Obtient le pointeur
     Result := pElement^;

end;

function TCollectionElementActionItem.DeleteSimple(Index: integer): boolean;
begin
    inherited Delete(Index);
end;

function TCollectionElementActionItem.Delete(Index: integer): boolean;
var pElement: PElementActionItem;
begin

    Result := false;

    if (Index < 0) or (Index >= Count) then
       // Hors limite
       exit;


    // Obtient le pointeur
    pElement := Items[Index];

    if pElement <> nil then
       // Libére la mémoire créée lors de l'ajout
       Dispose(pElement);

    // Supprime le pointeur de la liste
    inherited Delete(Index);

    // Met le resultat à True
    Result := true;

end;


function TCollectionElementActionItem.Add(Element: TElementActionItem): PElementActionItem;
var pElement: PElementActionItem;
begin
    
    Result := nil;
    
    New(pElement);          // Créer l'espace mémoire requis
    pElement^ := Element;   // Fait pointer l'élément
    
    try
       inherited Add(pElement);  // Ajoute le pointeur à la liste
       Result := pElement;
       CalculNiveauAtteint;
    except
       Result := nil;
    end;
    
    // Pour libérer la mémoire occupé par l'élément pointer:  Dispose(pElement);

end;

// Simple ajout de pointeur
procedure TCollectionElementActionItem.SimpleAdd(Pointeur: PElementActionItem);
begin
    
    inherited Add(Pointeur);  // Ajoute le pointeur à la liste
    
end;

function TCollectionElementActionItem.GetItemx(Index: integer): TElementActionItem;
var pElement: PElementActionItem;
begin

   if Count < 0 then exit;
   if Index >= Count then exit;

   pElement := Items[Index];
   Result := pElement^;

end;




end.
